#include "main.h" 


//****************************功能说明*********************************//
//                        GD32E230 Bootloader
//	当前版本 V1.0.0												更新时间:2025/7/5
//	by：陶鑫宇
//	主要功能如下：
//	[1]擦除flash程序										(直接擦除原有APP)
//	[2]串口IAP下载A区应用程序						(能够通过Xmodem协议,接收bin文件,并直接更新APP)
//	[3]设置OTA版本号										(设置当前运行程序的版本号,手动设置)
//	[4]查看OTA版本号										{查看当前运行程序的版本号}
//	[5]向外部flash下载程序							(通过Xmodem协议,接收bin文件,并分块存储(1~9),可实现多应用程序)
//	[6]使用外部flash中的程序						(从外部的flash中读取程序,并根据输入(1~9)刷新成当前的APP)
//	[7]重启															(软件重启设备)
//	[8]查看外部flash内存占用						(查看当前外部flash中每一块(1~9)中的程序所占用的字节数)
//*********************************************************************//


//****************************错误日志*********************************//
//				2025/6/17
//(严重bug上电就进空闲中断不停止，无相关资料，留作标记，有解决方案再改)
//暂时找不到原因，等我用STM32跑一遍程序试试
//				2025/6/19
//使用STM32出现同一问题，使用示波器排查后发现问题： 公司漏电！！！
//				2025/6/27
//USART、W25Q64、24C02、Flash擦写等功能验证完毕(暂未发现Debug)
//				2025/7/3
//特殊记录：STM32跳转前设置MSP，可以实现跳转
//					GD32跳转前如果设置了MSP，则无法实现正确跳转,
//					并会直接复位，注释后，可实现正常跳转
//Xmodem协议备注：在使用SecureCRT通过Xmodel协议发送bin文件时，无法通信
//			解决办法：必须使用大写字母'C',否则部分软件Xmodem不认(SecureCRT)
//*********************************************************************//

//需要保存的状态信息
OTA_InfoCB 	OTA_info;			//OTA信息
UpDataCB		updataA;			//应用程序更新信息

//状态机标志位
uint32_t BootStatuesFlag;  //每位定义，在main.h中


int main(void)
{
	//系统初始化 72Mhz
  systick_config();
	//初始化串口0
	MyUsart0_Init(921600);
	//初始化延迟定时器
	MySystick_init();
	//初始化I2C
	MyI2C_0_init();	
	//获取当前OTA信息
	MyW24C02_Read_BootloaderInfo();	
	printf("\r\n OTA_info.OTA_Flag=%x \r\n",OTA_info.OTA_Flag);	
	//初始化w25q64
	MyW25Q64_Init();
	//OTA分支判断
	MyBootLoader_Branch();

	while(1)
	{
		delay_1ms(10);
		//如果串口接收到了数据
		if(BL_CB.URxDataOut != BL_CB.URxDataIn)
		{
			//事件判断
			MyBootLoader_Event(BL_CB.URxDataOut->start,(BL_CB.URxDataOut->end - BL_CB.URxDataOut->start +1) );
			//输出指针下移
			BL_CB.URxDataOut++;
			//指针越界判断
			if(BL_CB.URxDataOut == BL_CB.URxDataEnd)
			{
				//重新指向缓冲区首地址
				BL_CB.URxDataOut = &BL_CB.URxDataPtr[0];
			}
		}
		//如果IAP_XMODEM_SENDC_FLAG被置位
		if(BootStatuesFlag & IAP_XMODEM_SENDC_FLAG)
		{
			//那么就每隔一段时间发送一个C,通知上位机发送数据
			if(updataA.XmodemTimer>=100)
			{
				printf("C");
				updataA.XmodemTimer = 0;
			}
			updataA.XmodemTimer++;
		}
		
		
		//如果更新应用程序标志位被挂起
		if(BootStatuesFlag & UPDATA_APPLICATION_FLAG)
		{
			printf("**********************************************\r\n");
			//输出要更新的应用程序大小
			printf("长度:%d byte\r\n",OTA_info.FireLen[updataA.W25Q64_xBlock]);
			printf("W25Q64_xBlock:%d \r\n",updataA.W25Q64_xBlock);
			//判断是否4字节对齐，未对齐会导致触发硬件错误中断
			if(OTA_info.FireLen[updataA.W25Q64_xBlock]%4 == 0)
			{
				printf("开始更新\r\n");
				//更新前先擦除原有程序
				GD32_EraseFlash(GD32_A_START_PAGE,GD32_A_PAGE_NUM);
				//先写入完整的一页，再处理未满的一页
				uint32_t i=0;
				for(i=0;i<OTA_info.FireLen[updataA.W25Q64_xBlock]/GD32_PAGE_SIZE;i++)
				{
					//按页读取要写入的块的内容
					MyW25Q64_Read(updataA.Updata_buffer,i*GD32_PAGE_SIZE+updataA.W25Q64_xBlock*64*1024,GD32_PAGE_SIZE);
					//按页写入到A区
					GD32_WriteFlash(GD32_A_SADDR+i*GD32_PAGE_SIZE,(uint32_t*)updataA.Updata_buffer,GD32_PAGE_SIZE);
					printf("已写入：%d %%  \r\n",(i*100)/(OTA_info.FireLen[updataA.W25Q64_xBlock]/GD32_PAGE_SIZE));
				}
				//处理未满的一页,判断是否还有内容
				if(OTA_info.FireLen[updataA.W25Q64_xBlock]%GD32_PAGE_SIZE != 0)
				{
					//读取剩余要写入的块的内容
					MyW25Q64_Read(updataA.Updata_buffer,i*GD32_PAGE_SIZE+updataA.W25Q64_xBlock*64*1024,OTA_info.FireLen[updataA.W25Q64_xBlock]%GD32_PAGE_SIZE);
					//将剩余内容写入到A区
					GD32_WriteFlash(GD32_A_SADDR+i*GD32_PAGE_SIZE,(uint32_t*)updataA.Updata_buffer,OTA_info.FireLen[updataA.W25Q64_xBlock]%GD32_PAGE_SIZE);
					printf("已写入：%d %%  \r\n",(i*100)/(OTA_info.FireLen[updataA.W25Q64_xBlock]/GD32_PAGE_SIZE));
				}
				//W25Q64_xBlock == 0表示是OTA更新的A区程序
				if(updataA.W25Q64_xBlock == 0)
				{
					//清除OTA标志位
					OTA_info.OTA_Flag = 0;
					//保存OTA相关信息
					MyW24C02_Write_BootloaderInfo();
				}
				printf("更新应用程序完成，当前使用的是块%d的程序,10ms后重启\r\n",updataA.W25Q64_xBlock);
				printf("**********************************************\r\n");
				delay_1ms(10);
				//复位中断系统
				nvic_system_reset();
			}
			else
			{
				printf("updata length error \r\n");
				//清除更新标志位
				BootStatuesFlag &= (~UPDATA_APPLICATION_FLAG);
			}		
		}
	}
    
}
